﻿#region Legal

// Jimmy Zimmerman
// Team Mongoose
//
// END USER LICENSE AGREEMENT
// IMPORTANT - READ THIS CAREFULLY:  This End User License Agreement is a legal agreement
// between you (either an individual, business entity, currently active identity of an
// individual with Multiple Personality Disorder, octopus overlord, or otherworldly entity),
// and Team Mongoose, for the enclosed, components.
//
// By reading this document and/or installing this product, you agree to be bound by the
// terms of this EULA.
//
// Team Mongoose owns all copyright, trade secret, trademark, trade wars,
// patent, portent, and potential rights to these components.  Team Mongoose
// grants you the right to deploy the enclosed components.
//
// If you agree to the terms of this EULA, a license to use these components is granted to you.
//
// If you should happen to benefit from the enclosed components, then you are legally and
// contractually bound to thank us for it. Send your regards to jimmyzimms@hotmail.com.
//
// OTHER RIGHTS AND LIMITATONS
// You may not reverse-engineer, decompile, decode, disassemble, psycho-analyze, or otherwise
// attempt to find hidden meanings between the lines of this EULA; unless, of course, you should
// happen to find some, and they are funny.
//
// You may not translate this EULA or any part of the components into Ancient Sumerian.
//
// THESE COMPONENTS ARE PROVIDED “AS-IS” WITHOUT WARRANTY OF ANY KIND. ANY USE OF THE COMPONENTS
// CONTAINED IS AT YOUR OWN RISK. TEAM MONGOOSE DISCLAIM ALL WARRANTIES, EITHER
// EXPRESS OR IMPLIED, WITH RESPECT TO THE ACCURRACY AND CORRECTNESS OF THE COMPONENTS CONTAINED
// HEREIN. TEAM MONGOOSE DOES NOT WARRANT THAT THE COMPONENTS ARE FLAWLESS.
//
// REDISTRIBUTION AND USE IN SOURCE AND BINARY FORMS, WITH OR WITHOUT MODIFICATION, ARE PERMITTED
// PROVIDED THAT THE FOLLOWING CONDITIONS ARE MET:
// * REDISTRIBUTIONS OF SOURCE CODE MUST RETAIN THE ABOVE COPYRIGHT NOTICE
// * REDISTRIBUTIONS IN BINARY FORM MUST NOTE THE USE OF THE COMPONENT IN DOCUMENTATION AND/OR
//   OTHER MATERIALS PROVIDED WITH THE DISTRIBUTION.
// * NEITHER THE NAME OF TEAM MONGOOSE MAY BE USED TO ENDORES OR PROMOTE PRODUCTS
//   DERIVED FROM THIS SOFTWARE WITHOUT SPECIFIC PRIOR WRITTEN PERMISSION.
//
// IN NO EVENT SHALL TEAM MONGOOSE BE HELD LIABLE FOR INCIDENTAL, SPECIAL, INDIRECT,
// INCONSEQUENTIAL, UNBELIEVABLE, EXAGGERATED, VERBOSE, OR TYPICAL DAMAGES INCURRED WHILE USING
// THE ENCLOSED COMPONENTS.
//
// OUR STUFF ALWAYS WORKS - SOMETIMES.

#endregion

using Microsoft.AnalysisServices.AdomdClient;
using System.ComponentModel;
using System.Data.Common;

namespace System.Data.MdxClient
{
    /// <summary>
    /// Represents a MDX statement or stored procedure to execute against a SQL Server Analysis Services database. 
    /// </summary>
    public class MdxCommand : DbCommand
    {
        #region Fields

        private readonly AdomdCommand command;
        private readonly MdxParameterCollection parameters;
        private MdxConnection connection;
        private MdxTransaction transaction;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the internal, native ADOMD.NET command associated with the parameters.
        /// </summary>
        /// <value>An <see cref="AdomdCommand"/> object.</value>
        protected internal AdomdCommand AdomdCommand
        {
            get
            {
                return this.command;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the object has been disposed.
        /// </summary>
        /// <value>True if the object has been disposed; otherwise, false.s</value>
        protected bool IsDisposed
        {
            get;
            private set;
        }

        #endregion

        #region Overrides

        /// <summary>
        /// Tries to cancel the execution of a <see cref="MdxCommand"/>.
        /// </summary>
        public override void Cancel()
        {
            this.command.Cancel();
        }

        /// <summary>
        /// Gets or sets the MDX statement or stored procedure to execute at the data source.
        /// </summary>
        /// <value>The MDX statement or stored procedure to execute. The default is an empty string.</value>
        public override string CommandText
        {
            get
            {
                return this.command.CommandText;
            }
            set
            {
                this.command.CommandText = value;
            }
        }

        /// <summary>
        /// Gets or sets the wait time before terminating the attempt to execute a command and generating an error.
        /// </summary>
        /// <value>The time in seconds to wait for the command to execute.</value>
        public override int CommandTimeout
        {
            get
            {
                return this.command.CommandTimeout;
            }
            set
            {
                this.command.CommandTimeout = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating how the <see cref="CommandText"/> property is to be interpreted.
        /// </summary>
        /// <value>One of the <see cref="CommandType"/> values. The default is <see cref="System.Data.CommandType.Text"/>.</value>
        public override CommandType CommandType
        {
            get
            {
                return this.command.CommandType;
            }
            set
            {
                this.command.CommandType = value;
            }
        }

        /// <summary>
        /// Creates a new instance of a <see cref="MdxParameter"/> object.
        /// </summary>
        /// <returns>A <see cref="MdxParameter"/> object.</returns>
        protected override DbParameter CreateDbParameter()
        {
            return new MdxParameter();
        }

        /// <summary>
        /// Gets or sets the connection associated with the command.
        /// </summary>
        /// <value>An <see cref="MdxConnection"/> object.</value>
        protected override DbConnection DbConnection
        {
            get
            {
                return this.connection;
            }
            set
            {
                this.connection = (MdxConnection) value;

                this.command.Connection = this.connection == null ? null : this.connection.AdomdConnection;
            }
        }

        /// <summary>
        /// Gets a collection of command parameters.
        /// </summary>
        /// <value>A <see cref="MdxParameterCollection"/> object.</value>
        protected override DbParameterCollection DbParameterCollection
        {
            get
            {
                return this.parameters;
            }
        }

        /// <summary>
        /// Gets or sets the <see cref="MdxTransaction"/> within which the <see cref="MdxCommand"/> executes.
        /// </summary>
        /// <value>A <see cref="MdxTransaction"/> object. The default value is null.</value>
        protected override DbTransaction DbTransaction
        {
            get
            {
                return this.transaction;
            }
            set
            {
                this.transaction = (MdxTransaction) value;

                if ( this.transaction == null )
                    ( (IDbCommand) this.command ).Transaction = null;
                else
                    ( (IDbCommand) this.command ).Transaction = this.transaction.AdomdTransaction;
            }
        }

        /// <summary>
        /// Hidden property used by the designers.
        /// </summary>
        /// <value>This property is not intended to be used in your code. It is used internally to support the designers.</value>
        [EditorBrowsable( EditorBrowsableState.Never )]
        [DefaultValue( true )]
        [DesignOnly( true )]
        [Browsable( false )]
        public override bool DesignTimeVisible
        {
            get
            {
                return true;
            }
            set
            {
            }
        }

        /// <summary>
        /// Releases the managed and, optionally, the unmanaged resources used by the <see cref="MdxCommand"/> class.
        /// </summary>
        /// <param name="disposing">Indicates whether the object is being disposed.</param>
        protected override void Dispose( bool disposing )
        {
            if ( this.IsDisposed )
                return;

            this.IsDisposed = true;
            this.command.Dispose();
            base.Dispose( disposing );
        }

        /// <summary>
        /// Sends the <see cref="CommandText"/> to the <see cref="DbConnection"/>, and builds a <see cref="MdxDataReader"/>
        /// using one of the <see cref="CommandBehavior"/> values.
        /// </summary>
        /// <param name="behavior">One of the <see cref="CommandBehavior"/> values.</param>
        /// <returns>A <see cref="MdxDataReader"/> object.</returns>
        protected override DbDataReader ExecuteDbDataReader( CommandBehavior behavior )
        {
            var reader = this.command.ExecuteReader( behavior );
            return new MdxDataReader( this.connection, reader, behavior );
        }

        /// <summary>
        /// Executes a MDX statement against the connection and returns the number of rows affected.
        /// </summary>
        /// <returns>The number of rows affected.</returns>
        public override int ExecuteNonQuery()
        {
            return this.command.ExecuteNonQuery();
        }

        /// <summary>
        /// Executes the query, and returns the first column of the first row in the result set
        /// returned by the query. Additional columns or rows are ignored.
        /// </summary>
        /// <returns>The first column of the first row in the result set, or a null reference if
        /// the result set is empty.</returns>
        public override object ExecuteScalar()
        {
            return this.command.ExecuteScalar();
        }

        /// <summary>
        /// Creates a prepared version of the command on an instance of SQL Server.
        /// </summary>
        public override void Prepare()
        {
            this.command.Prepare();
        }

        /// <summary>
        /// Returns a lifetime service object to maintain the lifetime of the component.
        /// </summary>
        /// <returns>A lifetime service object.</returns>
        public override object InitializeLifetimeService()
        {
            return this.command.InitializeLifetimeService();
        }

        /// <summary>
        /// Gets or sets the site of the component.
        /// </summary>
        /// <value>An <see cref="ISite"/> object.</value>
        public override ISite Site
        {
            get
            {
                return this.command.Site;
            }
            set
            {
                this.command.Site = value;
            }
        }

        /// <summary>
        /// Gets or sets how command results are applied to the <see cref="DataRow"/> when used by the
        /// <see cref="DbDataAdapter.Update(DataSet)"/> method of the <see cref="DbDataAdapter"/>.
        /// </summary>
        /// <value>One of the <see cref="UpdateRowSource"/> values.</value>
        public override UpdateRowSource UpdatedRowSource
        {
            get
            {
                return this.command.UpdatedRowSource;
            }
            set
            {
                this.command.UpdatedRowSource = value;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Instantiates a new instance of the <see cref="MdxCommand"/> class.
        /// </summary>
        /// <param name="command">The adapted <see cref="AdomdCommand"/> object.</param>
        /// <exception cref="ArgumentNullException"><paramref name="command"/> is null.</exception>
        protected internal MdxCommand( AdomdCommand command )
        {
            if ( ( this.command = command ) == null )
                throw new ArgumentNullException( "command" );

            this.parameters = new MdxParameterCollection( command );
        }

        /// <summary>
        /// Instantiates a new instance of the <see cref="MdxCommand"/> class.
        /// </summary>
        public MdxCommand()
            : this( new AdomdCommand() )
        {
        }

        #endregion
    }
}
